package com.bestcem.xm.award.controller;

import cn.hutool.core.lang.ObjectId;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.bestcem.xm.award.config.SignConfig;
import com.bestcem.xm.award.config.WxConfig;
import com.bestcem.xm.award.controller.convert.RedPacketConvert;
import com.bestcem.xm.award.controller.param.redpacket.DrawRedPacketReceiveParam;
import com.bestcem.xm.award.controller.param.redpacket.GetRedPacketDrawReceiveParam;
import com.bestcem.xm.award.controller.param.redpacket.WinDetailListQuery;
import com.bestcem.xm.award.controller.vo.FileInfoVO;
import com.bestcem.xm.award.controller.vo.redpacket.*;
import com.bestcem.xm.award.grpc.service.param.bonus.DrawRedPacketParam;
import com.bestcem.xm.award.grpc.service.param.redpacket.WinDetailListParam;
import com.bestcem.xm.award.service.RedPacketDisplayService;
import com.bestcem.xm.award.service.dto.*;
import com.bestcem.xm.common.core.constant.RegTypes;
import com.bestcem.xm.common.core.constant.ReqErrorCodeConstants;
import com.bestcem.xm.common.core.domain.web.ServiceResult;
import com.bestcem.xm.common.core.domain.web.XmResultJson;
import com.bestcem.xm.common.core.uitls.GRpcUtil;
import com.bestcem.xm.common.core.uitls.JsonUtil;
import com.bestcem.xm.common.core.uitls.SignUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * 微信红包奖励相关接口
 *
 * @author jie.yao <jie.yao@idiaoyan.com>
 * @version v3.0
 * @date 2021/8/17 14:13
 */
@Slf4j
@RestController
@RequestMapping(value = "/award/v3", produces = MediaType.APPLICATION_JSON_VALUE)
public class RedPacketDisplayController {

    private static final String SPLIT_CODE = "-";
    private static final int SPLIT_ARRAY_LENGTH_TWO = 2;

    @Resource
    private RedPacketDisplayService redPacketService;

    /**
     * 签名配置
     */
    @Autowired
    protected SignConfig signConfig;

    /**
     * 签名配置
     */
    @Autowired
    protected WxConfig wxConfig;

    /**
     * 获取投放数据统计(已不再使用)
     *
     * @param awardId 奖励id
     * @return 投放数据统计
     * @author jie.yao <jie.yao@idiaoyan.com>
     * @date 2021/8/17 15:33
     */
    @GetMapping("/bonus/deliver/detail")
    public XmResultJson<ListDeliverDetailVO> getDeliverStats(@RequestParam(value = "id") String awardId) {
        if (!ObjectId.isValid(awardId)) {
            return XmResultJson.fail(ReqErrorCodeConstants.PARAM_LOST, "id is required");
        }
        ServiceResult<List<DeliverDetailDTO>> serviceResult = redPacketService.getDeliverDetail(awardId);
        if (serviceResult.isSuccess()) {
            ListDeliverDetailVO listDeliverDetailVO = RedPacketConvert.deliverDetailConversion(serviceResult.getData());
            return XmResultJson.success(listDeliverDetailVO);
        } else {
            return XmResultJson.fail(1, serviceResult.getMsg());
        }
    }

    /**
     * 查看红包详情页面中的中奖名单
     *
     * @param awardId        奖励id
     * @param status         红包状态 0-7，8全部状态(页面使用)
     * @param page           页数
     * @param size           每页显示数据行数
     * @param deliverName    投放名称
     * @param deliverChannel 投放渠道 全部 0 ,二维码2，短信 3,微信公众号4,支付宝生活号5,邮件6
     * @param seq            答卷编号
     * @return 中奖名单分页数据
     * @author jie.yao <jie.yao@idiaoyan.com>
     * @date 2018/8/17 16:52
     */
    @GetMapping("/bonus/win/detail")
    public XmResultJson<WinDetailVO> listWinDetails(@RequestParam(value = "id") String awardId,
                                                    @RequestParam(value = "status", required = false) Integer status,
                                                    @RequestParam(value = "page", required = false) Integer page,
                                                    @RequestParam(value = "size", required = false) Integer size,
                                                    @RequestParam(value = "deliver_name", required = false) String deliverName,
                                                    @RequestParam(value = "deliver_channel", required = false) Integer deliverChannel,
                                                    @RequestParam(value = "seq", required = false) Long seq) {
        if (!ObjectId.isValid(awardId)) {
            return XmResultJson.fail(ReqErrorCodeConstants.PARAM_LOST, "id is required");
        }
        // 入参
        WinDetailListQuery query = new WinDetailListQuery(awardId, status, page, size, deliverName, deliverChannel, seq);
        // service层入参
        WinDetailListParam param = query.getWinDetailListParam();
        ServiceResult<WinDetailDTO> serviceResult = redPacketService.getWinDetailList(param);
        if (serviceResult.isSuccess()) {
            WinDetailVO winDetailVO = RedPacketConvert.winDetailConversion(serviceResult.getData(), param.getPage());
            return XmResultJson.success(winDetailVO);
        } else {
            return XmResultJson.fail(1, serviceResult.getMsg());
        }
    }

    /**
     * 导出红包中奖明细
     *
     * @param awardId        奖励id
     * @param status         红包状态 0-7，8全部状态(页面使用)
     * @param deliverName    投放名称
     * @param deliverChannel 投放渠道 全部 0 ,二维码2，短信 3,微信公众号4,支付宝生活号5,邮件6
     * @param seq            答卷编号
     * @return 中奖明细文件
     * @author jie.yao <jie.yao@idiaoyan.com>
     * @date 2018/8/17 17:51
     */
    @GetMapping("/bonus/win/export")
    public XmResultJson<FileInfoVO> exportRedPacketWin(@RequestParam(value = "id") String awardId,
                                                       @RequestParam(value = "status", required = false) Integer status,
                                                       @RequestParam(value = "deliver_name", required = false) String deliverName,
                                                       @RequestParam(value = "deliver_channel", required = false) Integer deliverChannel,
                                                       @RequestParam(value = "seq", required = false) Long seq) {
        if (!ObjectId.isValid(awardId)) {
            return XmResultJson.fail(ReqErrorCodeConstants.PARAM_LOST, "id is required");
        }
        // 入参
        WinDetailListQuery query = new WinDetailListQuery(awardId, status, null, null, deliverName, deliverChannel, seq);
        // service层入参
        WinDetailListParam param = query.getWinDetailListParam();
        ServiceResult<FileInfoDTO> serviceResult = redPacketService.exportWinDetailList(param);
        if (serviceResult.isSuccess()) {
            FileInfoVO fileInfoVO = RedPacketConvert.winExportFileInfoConversion(serviceResult.getData());
            return XmResultJson.success(fileInfoVO);
        } else {
            return XmResultJson.fail(1, serviceResult.getMsg());
        }
    }

    /**
     * 二维码后面的红包抽奖入口页
     *
     * @param requestId                    请求id
     * @param getRedPacketDrawReceiveParam award_id 奖励id，code 用户授权code
     * @return 奖励id等信息
     */
    @ApiOperation(value = "二维码后面的红包抽奖入口页")
    @PostMapping(value = "/bonus/entry/{request_id}")
    public XmResultJson<GetRedPacketDrawOuterVO> getRedPacketDraw(@PathVariable("request_id") String requestId, @RequestBody GetRedPacketDrawReceiveParam getRedPacketDrawReceiveParam) {
        // 校验是否有request_id
        if (StrUtil.isEmpty(requestId)) {
            return XmResultJson.fail(ReqErrorCodeConstants.PARAM_LOST, "没有request_id");
        }

        // request_id格式校验
        if (!Pattern.matches(RegTypes.OBJECT_ID, requestId)) {
            return XmResultJson.fail(5, "request_id格式错误");
        }

        // 校验 getRedPacketDrawReceiveParam 是否为null
        if (Objects.isNull(getRedPacketDrawReceiveParam)) {
            return XmResultJson.fail(ReqErrorCodeConstants.PARAM_LOST, "入参缺失");
        }

        // 参数校验
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(getRedPacketDrawReceiveParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            return XmResultJson.fail(ReqErrorCodeConstants.PARAM_FORMAT, violation.getMessage());
        }

        ServiceResult<RedPacketEntryDTO> result = redPacketService.getRedPacketDraw(getRedPacketDrawReceiveParam.getAwardId(), getRedPacketDrawReceiveParam.getCode(), requestId);

        if (result.isSuccess()) {
            // 构造 VO
            GetRedPacketDrawOuterVO getRedPacketDrawOuterVO
                    = RedPacketConvert.getRedPacketDrawConversion(result.getData(), requestId);

            GetRedPacketDrawVO info = getRedPacketDrawOuterVO.getInfo();
            // 生成签名
            // BONUS_KEY指的是该key
            String signKey = wxConfig.getKey();
            Map<String, Object> map = JsonUtil.convertValueSnake(info, new TypeReference<Map<String, Object>>() {
            });
            String sig = SignUtil.genSign(map, signKey);

            getRedPacketDrawOuterVO.setSig(sig);

            return XmResultJson.success(getRedPacketDrawOuterVO);
        } else {
            String msg = result.getMsg();
            if (StringUtils.isNotBlank(msg) && msg.contains(SPLIT_CODE) && msg.split(SPLIT_CODE).length == SPLIT_ARRAY_LENGTH_TWO) {
                String[] array = msg.split(SPLIT_CODE);
                Integer code = Integer.valueOf(array[0]);
                String errorMsg = array[1];
                return XmResultJson.fail(code, errorMsg);
            }
            return XmResultJson.fail(1, result.getMsg());
        }
    }

    /**
     * 红包抽奖
     *
     * @param requestId                 请求id
     * @param drawRedPacketReceiveParam award_id 奖励id，sig
     * @return 中奖金额
     */
    @ApiOperation(value = "红包抽奖")
    @PostMapping(value = "/bonus/draw/{request_id}")
    public XmResultJson<DrawRedPacketVO> drawRedPacket(@PathVariable("request_id") String requestId, @RequestBody DrawRedPacketReceiveParam drawRedPacketReceiveParam) {
        // 校验是否有request_id
        if (StrUtil.isEmpty(requestId)) {
            return XmResultJson.fail(ReqErrorCodeConstants.PARAM_LOST, "没有request_id");
        }

        // request_id格式校验
        if (!Pattern.matches(RegTypes.OBJECT_ID, requestId)) {
            return XmResultJson.fail(5, "request_id格式错误");
        }

        // 校验 drawRedPacketParam 是否为null
        if (Objects.isNull(drawRedPacketReceiveParam)) {
            return XmResultJson.fail(ReqErrorCodeConstants.PARAM_LOST, "入参缺失");
        }

        Map<String, Object> info = drawRedPacketReceiveParam.getInfo();

        // 校验 info 是否为null
        if (Objects.isNull(info)) {
            return XmResultJson.fail(ReqErrorCodeConstants.PARAM_LOST, "info缺失");
        }

        info.put("sig", drawRedPacketReceiveParam.getSig());

        // 验签
        String signKey = wxConfig.getKey();
        boolean respondentSign = SignUtil.checkSign(info, signKey);
        if (!respondentSign) {
            return XmResultJson.fail(ReqErrorCodeConstants.SIGN_ERROR, "invalid signature");
        }

        // 参数转换
        DrawRedPacketParam drawRedPacketParam = JSON.parseObject(JSON.toJSONString(drawRedPacketReceiveParam.getInfo()), DrawRedPacketParam.class);
        drawRedPacketParam.setRequestId(requestId);

        // 参数校验
        Set<ConstraintViolation<Object>> violations = GRpcUtil.validateParam(drawRedPacketParam);
        if (!CollectionUtils.isEmpty(violations)) {
            ConstraintViolation<Object> violation = violations.iterator().next();
            return XmResultJson.fail(ReqErrorCodeConstants.PARAM_FORMAT, violation.getMessage());
        }

        ServiceResult<Integer> serviceResult = redPacketService.drawRedPacket(drawRedPacketParam.getRequestId(), drawRedPacketParam.getAwardId());

        if (serviceResult.isSuccess()) {
            DrawRedPacketVO drawRedPacketVO = new DrawRedPacketVO(serviceResult.getData() == null ? 0 : serviceResult.getData());
            return XmResultJson.success(drawRedPacketVO);
        } else {
            String msg = serviceResult.getMsg();
            if (StringUtils.isNotBlank(msg) && msg.contains(SPLIT_CODE) && msg.split(SPLIT_CODE).length == SPLIT_ARRAY_LENGTH_TWO) {
                String[] array = msg.split("-");
                Integer code = Integer.valueOf(array[0]);
                String errorMsg = array[1];
                return XmResultJson.fail(code, errorMsg);
            }
            return XmResultJson.fail(1, serviceResult.getMsg());
        }
    }

    /**
     * 投放名称列表获取
     *
     * @param awardId 奖励id
     * @return 投放名称列表
     */
    @ApiOperation(value = "投放名称列表获取")
    @GetMapping(value = "/bonus/deliver/name")
    public XmResultJson<ListDeliverNamesVO> listDeliverNames(@ApiParam(value = "奖励id", required = true) @RequestParam(value = "id") String awardId) {

        // 校验是否有奖励id
        if (StrUtil.isEmpty(awardId)) {
            return XmResultJson.fail(ReqErrorCodeConstants.PARAM_LOST, "没有奖励id");
        }

        // 格式校验
        if (!Pattern.matches(RegTypes.OBJECT_ID, awardId)) {
            return XmResultJson.fail(5, "奖励id格式错误");
        }

        ServiceResult<List<String>> serviceResult = redPacketService.getDeliverNameList(awardId);

        if (serviceResult.isSuccess()) {
            ListDeliverNamesVO listDeliverNamesVO = new ListDeliverNamesVO(serviceResult.getData());
            return XmResultJson.success(listDeliverNamesVO);
        } else {
            return XmResultJson.fail(1, serviceResult.getMsg());
        }
    }

    /**
     * 获取红包总览
     *
     * @param awardId 奖励id
     * @return 红包总览
     */
    @ApiOperation(value = "获取红包总览")
    @GetMapping(value = "/bonus/overview")
    public XmResultJson<GetRedPacketStatsOuterVO> getRedPacketStats(@ApiParam(value = "奖励id", required = true) @RequestParam(value = "id") String awardId) {
        // 校验是否有奖励id
        if (StrUtil.isEmpty(awardId)) {
            return XmResultJson.fail(ReqErrorCodeConstants.PARAM_LOST, "没有奖励id");
        }

        // 格式校验
        if (!Pattern.matches(RegTypes.OBJECT_ID, awardId)) {
            return XmResultJson.fail(5, "奖励id格式错误");
        }

        ServiceResult<RedPacketStatsDTO> serviceResult = redPacketService.getRedPacketStats(awardId);
        if (serviceResult.isSuccess()) {
            GetRedPacketStatsOuterVO getRedPacketStatsOuterVO = RedPacketConvert.getRedPacketStatsConversion(serviceResult.getData());
            if (log.isInfoEnabled()) {
                log.info("[award] 红包总览参数转换:awardId:{},转换前:{},转换后:{}", awardId, JSON.toJSONString(serviceResult.getData()), JSON.toJSON(getRedPacketStatsOuterVO));
            }
            return XmResultJson.success(getRedPacketStatsOuterVO);
        } else {

            return XmResultJson.fail(1, serviceResult.getMsg());
        }
    }

    /**
     * 获取中奖人数
     *
     * @param awardId 奖励id
     * @return 中奖人数
     */
    @ApiOperation(value = "获取中奖人数")
    @GetMapping(value = "/bonus/win/count")
    public XmResultJson<CountWinnerVO> countWinner(@ApiParam(value = "奖励id", required = true) @RequestParam(value = "id") String awardId) {

        // 校验是否有奖励id
        if (StrUtil.isEmpty(awardId)) {
            return XmResultJson.fail(ReqErrorCodeConstants.PARAM_LOST, "没有奖励id");
        }

        // 格式校验
        if (!Pattern.matches(RegTypes.OBJECT_ID, awardId)) {
            return XmResultJson.fail(5, "奖励id格式错误");
        }

        ServiceResult<Integer> serviceResult = redPacketService.getWinCount(awardId);
        if (serviceResult.isSuccess()) {
            CountWinnerVO countWinnerVO = new CountWinnerVO(serviceResult.getData());
            return XmResultJson.success(countWinnerVO);
        } else {
            return XmResultJson.fail(1, serviceResult.getMsg());
        }
    }
}
